package com.behelpful.common.core.utils;


import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 断言工具类
 *
 * @author Alay
 * @date 2021-08-22 01:42
 * @since
 */
public final class IPredicates {

    public static <T> Predicate<T> and(Predicate<? super T> first, Predicate<? super T> second) {
        return new AndPredicate<>(ICollUtil.asList(first, second));
    }


    public static <T> Predicate<T> or(Iterable<? extends Predicate<? super T>> components) {
        return new OrPredicate<>(components);
    }


    public static <T> Predicate<T> not(Predicate<T> predicate) {
        return new NotPredicate<>(predicate);
    }


    public static <T> Predicate<T> in(Collection<? extends T> target) {
        return new InPredicate<>(target);
    }

    public static <T> Predicate<T> notIn(Collection<? extends T> target) {
        return new NotInPredicate<>(target);
    }


    public static <T> Predicate<T> isEqual(T t) {
        return new IsEqualPredicate<>(t);
    }

    public static <T, R> Predicate<R> isEqual(R compare, Function<T, R> function) {
        return new EqualPredicate(compare, function);
    }

    public static <T> Predicate<T> notEqual(T t) {
        return new NotEqualPredicate(t);
    }

    public static Predicate<String> equalsIgnoreCase(String target) {
        return new StrEqualsIgnoreCase(target);
    }


    public static <T> Predicate<T> notNull() {
        return new NotNullPredicate<>();
    }


    public static Predicate<String> notBlank() {
        return new NotBlankPredicate();
    }

    public static Predicate<String> startWith(String target) {
        return new StartWithPredicate(target);
    }

    // ###################### 断言内部类 #####################################

    private static class AndPredicate<T> implements Predicate<T>, Serializable {
        private final List<? extends Predicate<? super T>> components;
        private static final long serialVersionUID = 0L;

        private AndPredicate(List<? extends Predicate<? super T>> components) {
            this.components = components;
        }

        @Override
        public boolean test(T t) {
            for (Predicate<? super T> component : this.components) {
                if (!component.test(t)) {
                    return false;
                }
            }
            return true;
        }
    }


    private static class OrPredicate<T> implements Predicate<T>, Serializable {
        private final Iterable<? extends Predicate<? super T>> components;
        private static final long serialVersionUID = 0L;

        private OrPredicate(Iterable<? extends Predicate<? super T>> components) {
            this.components = components;
        }

        @Override
        public boolean test(T t) {
            for (Predicate<? super T> component : this.components) {
                if (component.test(t)) {
                    return true;
                }
            }
            return false;
        }

    }


    private static class NotPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        final Predicate<T> predicate;

        private NotPredicate(Predicate<T> predicate) {
            this.predicate = predicate;
        }

        @Override
        public boolean test(T t) {
            return !this.predicate.test(t);
        }
    }


    private static class InPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        private final Collection<?> target;

        private InPredicate(Collection<?> target) {
            this.target = target;
        }

        @Override
        public boolean test(T t) {
            try {
                return this.target.contains(t);
            } catch (NullPointerException var3) {
                return false;
            } catch (ClassCastException var4) {
                return false;
            }
        }
    }


    private static class NotInPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        private final Collection<?> target;

        private NotInPredicate(Collection<?> target) {
            this.target = target;
        }

        @Override
        public boolean test(T t) {
            return !this.target.contains(t);
        }
    }

    private static class IsEqualPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        private final T target;

        private IsEqualPredicate(T target) {
            this.target = target;
        }

        @Override
        public boolean test(T t) {
            return this.target.equals(t);
        }
    }

    /**
     * @param <T> 入参类型
     * @param <R> function.apply() 返回值类型也是比较对象的类型
     */
    private static class EqualPredicate<T, R> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        private final Function<T, R> function;
        private final R compare;

        private EqualPredicate(R compare, Function<T, R> function) {
            this.function = function;
            this.compare = compare;
        }

        @Override
        public boolean test(T source) {
            return function.apply(source).equals(compare);
        }

    }


    private static class NotEqualPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;
        private T target;

        private NotEqualPredicate(T target) {
            this.target = target;
        }

        @Override
        public boolean test(T t) {
            return !this.target.equals(t);
        }
    }

    /**
     * 不为 Null
     *
     * @param <T>
     */
    private static class NotNullPredicate<T> implements Predicate<T>, Serializable {
        private static final long serialVersionUID = 0L;

        private NotNullPredicate() {
        }

        @Override
        public boolean test(T t) {
            return null != t;
        }
    }

    private static class NotBlankPredicate implements Predicate<String>, Serializable {
        private static final long serialVersionUID = 0L;

        private NotBlankPredicate() {
        }

        @Override
        public boolean test(String t) {
            if (t == null) {
                return false;
            }
            // 去除空格
            t = t.replace(" ", "");
            return t.length() > 0;
        }
    }


    private static class StrEqualsIgnoreCase implements Predicate<String>, Serializable {
        private static final long serialVersionUID = 0L;
        private final String target;

        private StrEqualsIgnoreCase(String target) {
            this.target = target;
        }

        @Override
        public boolean test(String t) {
            return this.target.equalsIgnoreCase(t);
        }
    }

    private static class StartWithPredicate implements Predicate<String>, Serializable {

        private final String target;

        private StartWithPredicate(String target) {
            this.target = target;
        }

        @Override
        public boolean test(String t) {
            return t.startsWith(target);
        }
    }


}